package de.bht.fb6.cg1.exercise3.implement;


import java.lang.reflect.Array;

import de.bht.fb6.cg1.exercise3.Matrix;
import de.bht.fb6.cg1.exercise3.Ring;
import de.bht.fb6.cg1.exercise3.RowVector;

/**
 * a row vector implementation
 *
 * @param <T> internal value type
 */
@SuppressWarnings("serial")
public class RowVectorImpl<T extends Number> extends MatrixImpl<T> implements RowVector<T> {
	/**
	 * Creates a row vector to a given two-dimensional array.
	 * 
	 * @param <R>   RingType of the row vector
	 * @param type  Type of the values
	 * @param vals  Values of the row vector
	 */
	public RowVectorImpl(final T[][] vals, final Class<? extends Ring<T>> rClass) {
		super(vals, rClass);
		if (getRows() != 1) {
			throw new IllegalArgumentException("row vector only has 1 row");
		}
	}

	/**
	 * Copys a row vector.
	 *
	 * @param vals values to set
	 * @param rClass the used ringclass
	 */
	public RowVectorImpl(final Matrix<T> vals, final Class<? extends Ring<T>> rClass) {
		super(vals, rClass);
	}

	/**
	 * create a new row vector from ringtypes
	 * 
	 * @param vals ringtypes to set on initialise.
	 */
	public RowVectorImpl(final Ring<T>[][] vals) {
		super(vals);
	}

	/**
	 * copy from a {@link MatrixImpl}
	 * @param A default values to set
	 */
	public RowVectorImpl(final MatrixImpl<T> A) {
		super(A);
	}

	/**
	 * Calculates the cross product of the given {@link RowVector}s.
	 * 
	 * @param vectors The vectors for the cross product. The amount of vectors must be dimension - 2. Must not be null.
	 * @return The cross product of the vectors.
	 */
	@SuppressWarnings("unchecked")
	@Override
	public RowVector<T> crossProduct(final RowVector<T>... vectors) {
		if (vectors.length != getColumns()-2) {
			throw new IllegalArgumentException("Not enough vectors to build crossproduct.");
		}

		final RowVectorRing<T>[][] values = (RowVectorRing<T>[][]) Array.newInstance(RowVectorRing.class, getColumns(), getColumns());
		for (int col = 0; col < getColumns(); col++) {
			final Ring<T>[][] e_values = newRingArray(1, getColumns());
			for (int i = 0; i < getColumns(); i++) {
				e_values[0][i] = RingZero();
			}
			e_values[0][col] = RingOne();

			values[0][col] = new RowVectorRing<T>(new RowVectorImpl<T>(e_values));
		}

		for (int col = 0; col < getColumns(); col++) {
			final Ring<T>[][] v_values = newRingArray(1,1);
			v_values[0][0] = getRing(0,col);
			values[1][col] = new RowVectorRing<T>(new RowVectorImpl<T>(v_values));
		}

		for (int row = 2; row < getColumns(); row++) {
			for (int col = 0; col < getColumns(); col++) {
				final Ring<T>[][] v_values = newRingArray(1,1);
				v_values[0][0] = newRingValue(vectors[row - 2].get(0, col));
				values[row][col] = new RowVectorRing<T>(new RowVectorImpl<T>(v_values));
			}
		}

		final SquareMatrixImpl<RowVectorImpl<T>> A = new SquareMatrixImpl<RowVectorImpl<T>>(values);
		return new RowVectorImpl<T>(A.getDeterminant().getTransposed(), getRingClass());
	}

	/**
	 * calculate the dot product of both vectors
	 * 
	 * @param vector The second vector.
	 * @return The dot product.
	 */
	@Override
	public T dotProduct(final RowVector<T> vector) {
		if (getColumns() != vector.getColumns()) {
			throw new IllegalArgumentException("Invalid vector size");
		}

		return mult(vector.getTransposed()).get(0, 0);
	}

}
